﻿using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;

namespace OpenCompiler.Scanning.Scanners
{
	public unsafe class StringMatchTokenScanner : TokenScanner
	{
		private object[] _grammar;
		private string[] _grammarStrings;
		private char*[] _grammarAsStrings;
		private int[] _grammarLengths;

		protected StringMatchTokenScanner()
		{
			this.ValidGrammar = new Dictionary<object, string>();
			
		}

		protected void AddGrammar(object grammar, string stringToMatch)
		{
			this.ValidGrammar[grammar] = stringToMatch;
		}

		public Dictionary<object, string> ValidGrammar { get; private set; }

		protected virtual string Prefix { get { return string.Empty; } }

		protected void Initialize()
		{
			this._grammar = this.ValidGrammar.Keys.ToArray();
			this._grammarStrings = this.ValidGrammar.Values.ToArray();
			this._grammarAsStrings = new char*[this._grammar.Length];
			this._grammarLengths = new int[this._grammar.Length];
			for (var index = 0; index < this._grammar.Length; index++)
			{
				var actualGrammarString =
					(this.Prefix.Length > 0)
						?
							string.Format("{0}{1}", this.Prefix, this._grammarStrings[index])
						:
							this._grammarStrings[index];
			
				this._grammarAsStrings[index] = (char*)Marshal.StringToBSTR(actualGrammarString);
				this._grammarLengths[index] = actualGrammarString.Length;
			}
		}


		public override bool IsToken(char* stringPointer, int remainingCharacters)
		{
			for (var index = 0; index < this._grammarAsStrings.Length; index++)
			{
				if (TokenHelper.IsMatch(stringPointer, remainingCharacters, this._grammarAsStrings[index], this._grammarLengths[index]))
				{
					return true;
				}
			}
			return false;
		}

		public override object GetToken(ref char* stringPointer, int remainingCharacters)
		{
			for (var index = 0; index < this._grammarAsStrings.Length; index++)
			{
				if (TokenHelper.IsMatch(stringPointer, remainingCharacters, this._grammarAsStrings[index], this._grammarLengths[index]))
				{
					stringPointer += this._grammarLengths[index];
					return this._grammar[index];
				}
			}
			return null;
		}
	}
}
